package com.neotech.neo4j.embeded;

import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.IndexManager;
import org.neo4j.kernel.EmbeddedGraphDatabase;

import com.neotech.neo4j.Neo4j;
import com.neotech.neo4j.resources.Item;
import com.neotech.neo4j.resources.ItemType;
import com.neotech.neo4j.rest.Neo4jREST;
import com.neotech.neo4j.utils.Constants;

public class Neo4jEmbeded extends Neo4j{
	private static Logger log = Logger.getLogger(Neo4jEmbeded.class.getName());

	public GraphDatabaseService graphDb;
	private IndexManager index;
	private String location;
	private boolean opened;
	
	public Neo4jEmbeded(String location) {
		this.location = location;
		log.debug(":: Creating Neo4j Embeded ::");
	}
	
	public void open(){
		if(!opened){
			graphDb = new EmbeddedGraphDatabase( location );
			index = graphDb.index();
			opened = true;
			log.debug(":: Opening neo4j ::");
		}
	}
	
	public void close(){
		if(opened){
			graphDb.shutdown();
			opened = false;
			log.debug(":: Closing neo4j ::");
		}
	}

	public Long createNode() {
		open();
		Node node = null;
		Transaction tx = graphDb.beginTx();
		try{
			node = graphDb.createNode();
			tx.success();
		}catch (Exception e) {
			log.error(e.getMessage());
		}finally{
		    tx.finish();
		}
		return (node == null)? null : node.getId();
	}

	public Long createNode(String name) {
		Node node = graphDb.createNode();
		node.setProperty(Constants.NAME, name);
		return node.getId();
	}

	public Long createNode(String name, String value) {
		return graphDb.createNode().getId();
	}

	public void addPropertyToNode(Long id, String propertyName,
			String propertyValue) {
		open();
		Transaction tx = graphDb.beginTx();
		try{
			graphDb.getNodeById(id).setProperty(propertyName, propertyValue);
			tx.success();
		}catch (Exception e) {
			log.error(e.getMessage());
		}finally{
		    tx.finish();
		}
	}

	//TODO
	public void addPropertyToRelationship(Long id, String propertyName,
			String propertyValue) {
	}

	//TODO
	public Long addRelationship(Long nodeFrom, Long nodeTo, String relName) {
		open();
		Node from = graphDb.getNodeById(nodeFrom);
		Node to = graphDb.getNodeById(nodeTo);
		Relationship rel = null;
		Transaction tx = graphDb.beginTx();
		try{
			rel = from.createRelationshipTo(to, new MyRelationshipType(relName));
			tx.success();
		}catch (Exception e) {
			log.error(e.getMessage());
		}finally{
		    tx.finish();
		}
		return (rel == null) ? null : rel.getId();
	}

	//TODO relationship
	public Item getItemById(Long id, ItemType type) {
		Item item = new Item(id);
		if(type == ItemType.NODE){
			Node node = graphDb.getNodeById(id);
			Iterator<String> properties = node.getPropertyKeys().iterator();
			while(properties.hasNext()){
				String property = properties.next();
				item.addProperty(property, node.getProperty(property).toString());
			}
		}
		return item;
	}

	public Long getRootNode() {
		return 0L;
	}

	//TODO
	public String getPropertyValue(Long id, String propertyName, ItemType type) {
		return null;
	}

	//TODO
	public void indexNode(Long id, String indexName, String indexKey,
			String indexValue) {
	}

	public void addToIndex(Long id, String indexName, String indexKey,
			String indexValue, ItemType type) {
		if(type == ItemType.NODE){
			Index<Node> i = index.forNodes(indexKey) ;
			i.add(graphDb.getNodeById(id), indexName, indexValue);
		}else{
			Index<Relationship> i = index.forRelationships(indexKey) ;
			i.add(graphDb.getRelationshipById(id), indexName, indexValue);
		}
	}

	public ArrayList<Item> queryIndex(String indexName, String propertyName,
			String propertyValue, ItemType type) {
		return null;
	}

	public void deleteItem(Long id, ItemType type) {
		if(type == ItemType.NODE)
			graphDb.getNodeById(id).delete();
		else
			graphDb.getRelationshipById(id).delete();
	}
	
	public GraphDatabaseService getGraphDb(){
		return graphDb;
	}

}
